 /*******************************************************************************
  * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.update.internal.ui.model;

 import java.io.*;
 import java.net.*;
 import java.util.ArrayList ;
 import java.util.StringTokenizer ;
 import java.util.Vector ;

 import javax.xml.parsers.*;

 import org.eclipse.core.runtime.*;
 import org.eclipse.update.internal.core.*;
 import org.eclipse.update.internal.ui.*;
 import org.w3c.dom.*;
 import org.xml.sax.*;

 public class BookmarkUtil {
     private static final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

     public static void parse(String fileName, Vector bookmarks) {
         File file = new File(fileName);
         if (!file.exists())
             return;

         try {
             documentBuilderFactory.setNamespaceAware(true);
             DocumentBuilder parser = documentBuilderFactory.newDocumentBuilder();
             Document doc = parser.parse(file);
             Node root = doc.getDocumentElement();
             processRoot(root, bookmarks);
         } catch (ParserConfigurationException e) {
             UpdateUI.logException(e);
         } catch (SAXException e) {
             UpdateUI.logException(e);
         } catch (IOException e) {
             UpdateUI.logException(e);
         }
     }

     public static SiteBookmark[] getBookmarks(Vector bookmarks) {
         ArrayList result = new ArrayList ();
         for (int i = 0; i < bookmarks.size(); i++) {
             processEntry(bookmarks.get(i), result);
         }
         return (SiteBookmark[]) result.toArray(new SiteBookmark[result.size()]);
     }

     public static BookmarkFolder getFolder(Vector bookmarks, IPath path) {
         NamedModelObject object = find(bookmarks, path);
         if (object != null && object instanceof BookmarkFolder)
             return (BookmarkFolder) object;
         return null;
     }

     public static NamedModelObject find(Vector bookmarks, IPath path) {
         Object [] array = bookmarks.toArray();
         return find(array, path);
     }

     private static NamedModelObject find(Object [] array, IPath path) {
         String name = path.segment(0);
         for (int i = 0; i < array.length; i++) {
             NamedModelObject obj = (NamedModelObject) array[i];
             if (obj.getName().equals(name)) {
                 if (obj instanceof BookmarkFolder) {
                     if (path.segmentCount() > 1) {
                         IPath childPath = path.removeFirstSegments(1);
                         BookmarkFolder folder = (BookmarkFolder) obj;
                         return find(folder.getChildren(null), childPath);
                     }
                 }
                 return obj;
             }
         }
         return null;
     }

     private static void processRoot(Node root, Vector bookmarks) {
         if (root.getNodeName().equals("bookmarks")) { //$NON-NLS-1$
 NodeList children = root.getChildNodes();
             processChildren(children, null, bookmarks);
         }
     }
     private static void processChildren(
         NodeList children,
         BookmarkFolder folder,
         Vector bookmarks) {
         UpdateModel model = UpdateUI.getDefault().getUpdateModel();
         for (int i = 0; i < children.getLength(); i++) {
             Node child = children.item(i);
             NamedModelObject object = null;
             if (child.getNodeType() == Node.ELEMENT_NODE) {
                 if (child.getNodeName().equals("site")) { //$NON-NLS-1$
 object = createSite(child);
                 } else if (child.getNodeName().equals("folder")) { //$NON-NLS-1$
 object = createFolder(child);
                 }
             }
             if (object != null) {
                 if (folder != null) {
                     folder.addChild(object);
                 } else {
                     bookmarks.add(object);
                 }
                 object.setModel(model);
             }
         }
     }

     private static SiteBookmark createSite(Node child) {
         String name = getAttribute(child, "name"); //$NON-NLS-1$
 URL url = null;
         try {
             url = new URL(getAttribute(child, "url")); //$NON-NLS-1$
 } catch (MalformedURLException e) {
         }

         String web = getAttribute(child, "web"); //$NON-NLS-1$
 boolean webBookmark = (web != null && web.equals("true")); //$NON-NLS-1$

         String sel = getAttribute(child, "selected"); //$NON-NLS-1$
 boolean selected = (sel != null && sel.equals("true")); //$NON-NLS-1$

         SiteBookmark bookmark = new SiteBookmark(name, url, webBookmark, selected);

         String local = getAttribute(child, "local"); //$NON-NLS-1$
 bookmark.setLocal(local != null && local.equals("true")); //$NON-NLS-1$

         String ign = getAttribute(child, "ignored-categories"); //$NON-NLS-1$
 if (ign != null) {
             StringTokenizer stok = new StringTokenizer (ign, ","); //$NON-NLS-1$
 ArrayList array = new ArrayList ();
             while (stok.hasMoreTokens()) {
                 String tok = stok.nextToken();
                 array.add(tok);
             }
             bookmark.setIgnoredCategories((String []) array.toArray(new String [array.size()]));
         }
         // read description
 NodeList children = child.getChildNodes();
         for (int i = 0; i < children.getLength(); i++) {
             Node node = children.item(i);
             if (node.getNodeType() == Node.ELEMENT_NODE) {
                 bookmark.setDescription(createDescription(node));
                 break;
             }
         }
         return bookmark;
     }

     private static String createDescription(Node child) {
         String description = ""; //$NON-NLS-1$
 NodeList children = child.getChildNodes();
         for (int i = 0; i < children.getLength(); i++) {
             Node node = children.item(i);
             if (node.getNodeType() == Node.TEXT_NODE)
                 description += node.getNodeValue();
         }
         return description;
     }

         
     private static BookmarkFolder createFolder(Node child) {
         BookmarkFolder folder = new BookmarkFolder();
         String name = getAttribute(child, "name"); //$NON-NLS-1$
 folder.setName(name);
         if (child.hasChildNodes())
             processChildren(child.getChildNodes(), folder, null);
         return folder;
     }

     public static void store(String fileName, Vector bookmarks) {
         FileOutputStream fos = null;
         OutputStreamWriter osw = null;
         PrintWriter writer = null;
         try {
             fos = new FileOutputStream(fileName);
             osw = new OutputStreamWriter(fos, "UTF8"); //$NON-NLS-1$
 writer = new PrintWriter(osw);
             writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); //$NON-NLS-1$
 writer.println("<bookmarks>"); //$NON-NLS-1$
 for (int i = 0; i < bookmarks.size(); i++) {
                 Object obj = bookmarks.get(i);
                 writeObject(" ", obj, writer); //$NON-NLS-1$
 }
         } catch (IOException e) {
             UpdateUI.logException(e, false);
         } finally {
             writer.println("</bookmarks>"); //$NON-NLS-1$
 writer.flush();
             writer.close();
             try {
                 if (osw != null)
                     osw.close();
             } catch (IOException e1) {
                 UpdateUI.logException(e1, false);
             }
             try {
                 if (fos != null)
                     fos.close();
             } catch (IOException e2) {
                 UpdateUI.logException(e2, false);
             }
         }
     }
     private static void writeObject(
         String indent,
         Object obj,
         PrintWriter writer) {
         if (obj instanceof SiteBookmark) {
             SiteBookmark bookmark = (SiteBookmark) obj;
             String name = bookmark.getName();
             String url = bookmark.getURL().toString();
             String web = bookmark.isWebBookmark()?"true":"false"; //$NON-NLS-1$ //$NON-NLS-2$
 String sel = bookmark.isSelected()?"true":"false"; //$NON-NLS-1$ //$NON-NLS-2$
 String local = bookmark.isLocal() ? "true" : "false"; //$NON-NLS-1$ //$NON-NLS-2$
 String [] ign = bookmark.getIgnoredCategories();
             StringBuffer wign = new StringBuffer ();
             for (int i = 0; i < ign.length; i++) {
                 if (i > 0)
                     wign.append(',');
                 wign.append(ign[i]);
             }
             writer.print(indent + "<site name=\"" + UpdateManagerUtils.getWritableXMLString(name) + "\" url=\"" + url + "\" web=\"" + web + "\" selected=\"" + sel + "\" local=\"" + local + "\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
 if (wign.length() > 0)
                 writer.print(" ignored-categories=\""+wign.toString()+"\""); //$NON-NLS-1$ //$NON-NLS-2$
 if (bookmark.getDescription() != null) {
                 writer.println(">"); //$NON-NLS-1$
 writer.print(indent+" <description>"); //$NON-NLS-1$
 writer.print(UpdateManagerUtils.getWritableXMLString(bookmark.getDescription()));
                 writer.println("</description>"); //$NON-NLS-1$
 writer.println(indent +"</site>"); //$NON-NLS-1$
 } else {
                 writer.println("/>"); //$NON-NLS-1$
 }
         } else if (obj instanceof BookmarkFolder) {
             BookmarkFolder folder = (BookmarkFolder) obj;
             String name = folder.getName();
             writer.println(indent + "<folder name=\"" + UpdateManagerUtils.getWritableXMLString(name) + "\">"); //$NON-NLS-1$ //$NON-NLS-2$
 Object [] children = folder.getChildren(folder);
             String indent2 = indent + " "; //$NON-NLS-1$
 for (int i = 0; i < children.length; i++) {
                 writeObject(indent2, children[i], writer);
             }
             writer.println(indent + "</folder>"); //$NON-NLS-1$
 }
     }

     private static String getAttribute(Node node, String name) {
         NamedNodeMap atts = node.getAttributes();
         Node att = atts.getNamedItem(name);
         if (att != null) {
             return att.getNodeValue();
         }
         return ""; //$NON-NLS-1$
 }
     private static void processFolder(BookmarkFolder folder, ArrayList result) {
         Object [] children = folder.getChildren(folder);
         for (int i = 0; i < children.length; i++) {
             processEntry(children[i], result);
         }
     }
     private static void processEntry(Object obj, ArrayList result) {
         if (obj instanceof SiteBookmark)
             result.add(obj);
         else if (obj instanceof BookmarkFolder) {
             processFolder((BookmarkFolder) obj, result);
         }
     }
 }

